#include "bsp_iic.h"

void IIC_GPIO_Init(void) {
  IOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_GPIO1_IO29, 0);
  IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_GPIO1_IO29, 0x70b0);
  IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_GPIO1_IO28, 0);
  IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_GPIO1_IO28, 0x70b0);
  gpio_pin_config_t config;
  config.direction = kGPIO_DigitalOutput;
  config.outputLogic = 1;
  config.interruptMode = kGPIO_NoIntmode;
  gpio_init(GPIO1, 29, &config);
  gpio_init(GPIO1, 28, &config);
  IIC_DELAY_MS(5);
}

void IIC_Start() {
  SCL_OUTPUT_LEVEL(HIGH);
  SDA_OUTPUT_LEVEL(HIGH);
  IIC_DELAY_MS(5);
  SDA_OUTPUT_LEVEL(LOW);
  IIC_DELAY_MS(5);
}

void IIC_Stop() {
  SCL_OUTPUT_LEVEL(LOW);
  SDA_OUTPUT_LEVEL(LOW);
  IIC_DELAY_MS(5);
  SCL_OUTPUT_LEVEL(HIGH);
  IIC_DELAY_MS(5);
  SDA_OUTPUT_LEVEL(HIGH);
  IIC_DELAY_MS(5);
}

void IIC_Write_Data(uint_fast8_t data) {
  SCL_OUTPUT_LEVEL(LOW);
  int i;
  uint_fast8_t level;
  for (i = 0; i < 8; i++) {
    // 由高到低去写
    level = (data >> 7) & 1;
    SDA_OUTPUT_LEVEL(level);
    IIC_DELAY_MS(5);
    SCL_OUTPUT_LEVEL(HIGH);
    IIC_DELAY_MS(5);
    SCL_OUTPUT_LEVEL(LOW);
    data = data << 1;
  }
}

uint_fast8_t IIC_Read_Data() {
  uint_fast8_t data = 0;
  // 设置SDA的模式为输入
  SDA_IN_MODE();
  // 设置SCL的电平状态
  SCL_OUTPUT_LEVEL(LOW);
  IIC_DELAY_MS(5);
  // MSB先写
  int i;
  for (i = 0; i < 8; i++) {
    SCL_OUTPUT_LEVEL(HIGH);
    IIC_DELAY_MS(1);
    int level = SDA_INPUT_LEVEL();
    data <<= 1;
    data |= level;
    SCL_OUTPUT_LEVEL(LOW);
    IIC_DELAY_MS(1);
  }
  SDA_OUT_MODE();
  return data;
}

// 接收端向发送端发送ACK
void IIC_Write_ACK() {
  // 将SCL和SDA拉低
  SCL_OUTPUT_LEVEL(LOW);
  SDA_OUTPUT_LEVEL(LOW);
  IIC_DELAY_MS(5);
  // SDA保持低电平，SCL切换到高电平
  SCL_OUTPUT_LEVEL(HIGH);
  IIC_DELAY_MS(5);
}
// 接收端向发送端发送NACK
void IIC_Write_NACK() {
  // 将SCL和SDA拉低
  SCL_OUTPUT_LEVEL(LOW);
  SDA_OUTPUT_LEVEL(HIGH);
  IIC_DELAY_MS(5);
  // SDA保持高电平，SCL切换到高电平
  SDA_OUTPUT_LEVEL(HIGH);
  IIC_DELAY_MS(5);
}

// 等待接收端向发送端发送应答信号
int IIC_Read_ACK() {
  // SDA为输入
  SDA_IN_MODE();
  SCL_OUTPUT_LEVEL(LOW);
  IIC_DELAY_MS(5);
  SCL_OUTPUT_LEVEL(HIGH);
  IIC_DELAY_MS(5);

  int timeout = 0;
  int level = 0;
  do {
    level = SDA_INPUT_LEVEL();
    IIC_DELAY_MS(1); // 两次读或写操作之间需要延时
    timeout++;
    if (timeout > 50) {
      printf("          data transmit stop!\r\n");
      IIC_Stop();
      return -1;
    }
  } while (level);
  SDA_OUT_MODE();
  return 0;
}
